package utils

import (
	"github.com/gogf/gf/encoding/gjson"
	"github.com/gogf/gf/errors/gerror"
	"github.com/gogf/gf/util/gconv"
	"github.com/golang-jwt/jwt"
	"time"
)

const (
	SECRET       = "546L5b2q5pyA54mb6YC877yM6Jm+57Gz5bCP56uZ5LiA5a6a5Y+v5Lul" //nolint:gosec    // 密钥
	JwtKeyExpire = "expireAt"
	JwtKeyUser   = "user"
)

type CustomClaims struct {
	ID       uint   `json:"id"`
	Email    string `json:"email"`
	Username string `json:"username"`
	jwt.StandardClaims
}

// CreateToken 创建token
func CreateToken(claims CustomClaims, expireAt time.Time) (string, error) {
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		JwtKeyUser:   gjson.New(claims),
		JwtKeyExpire: expireAt,
	})
	tokenString, err := token.SignedString([]byte(SECRET))
	if err != nil {
		panic(gerror.Wrap(err, "创建token失败"))
	}

	return tokenString, nil
}

// ParseToken 解析token
func ParseToken(token string) (*jwt.Token, error) {
	claim, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
		return []byte(SECRET), nil
	})
	if err != nil {
		panic(gerror.Wrap(err, "解析token失败"))
	}
	if claim.Valid {
		return claim, nil
	}
	return nil, gerror.New("token无效")
}

func RefreshToken(tokenString string) (string, error) {
	jwt.TimeFunc = func() time.Time {
		return time.Unix(0, 0)
	}
	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		return []byte(SECRET), nil
	})
	if err != nil {
		return "", err
	}
	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		jwt.TimeFunc = time.Now
		var customClaims CustomClaims
		err := gconv.Scan(claims[JwtKeyUser], &customClaims)
		if err != nil {
			panic(gerror.Wrap(err, "解析token失败"))
			return "", err
		}
		return CreateToken(customClaims, time.Now().Add(10*time.Minute))
	}
	return "", gerror.New("token 无效")
}
